using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Web.UI.Design;

using PHSRAG.Insight21.CDS;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.ClinicalTrials;
using PHSRAG.Utility;

namespace PHSRAG.Insight21.InsightWebControls.ClinicalTrials
{
    /// <summary>
    /// The Budget Procedure Control is used to provide a user interface for a single Budget Procedure.
    /// </summary>
    [ToolboxData("<{0}:BudgetProcedureControl runat=server></{0}:BudgetProcedureControl>"), Designer(typeof(BudgetProcedureControlDesigner))]
    public class BudgetProcedureControl : System.Web.UI.WebControls.TableRow, INamingContainer
    {
        #region Instance Variables
        private BudgetProcedure budgetProcedure;
//        private TableRow tr;
        private TextBox procedureChargeCode;
        private TextBox procedureUseHospitalPricing;
        private TextBox procedureFacilityPricing;
        private Label procedureName;
        private Label procedureSpace;
        private CheckBox applyOverhead;
        private CheckBox inpatient;
        private CheckBox delete;
        private TextBox profFee;
        private Label charge;
        private Label researchCharge;
        private TextBox procedureCharge;
        private CheckBox selectAllProcReq;
        private CheckBox selectAllProcSOC;
        private ArrayList requiredList = new ArrayList();
        private ArrayList standardOfCareList = new ArrayList();
        private CompareValidator procedureValidator;
        private RequiredFieldValidator profFeeRequiredValidator;
        private RegularExpressionValidator profFeeFormatValidator;
        private RequiredFieldValidator procedureChargeRequiredValidator;
        private RegularExpressionValidator procedureChargeFormatValidator;
        private Budget budget;
        #endregion

        #region Constants
        private const string controlHost = "../Common/ControlHost.aspx?Load=";
        private const string pickerURL = "../ClinicalTrials/Controls/ProcedurePicker.ascx";
        private const string features = "'width=800,height=600,scrollbars=yes,resizable=yes,status=no'";
        /// <summary>
        /// Indicates how many columns are to the left of the Visits
        /// </summary>
        private const int totalColumnOffset = 8;
        #endregion

        #region Public Methods
        /// <summary>
        /// Returns an indicator showing whether the procedure is required for a given visit
        /// </summary>
        /// <param name="index">Visit index</param>
        /// <returns>bool</returns>
        public bool GetRequired(int index)
        {
            return ((CheckBox)requiredList[index]).Checked;
        }

        /// <summary>
        /// Returns an indicator showing whether the procedure is part of the standard of care for a given visit
        /// </summary>
        /// <param name="index"></param>
        /// <returns>bool</returns>
        public bool GetStandardOfCare(int index)
        {
            return ((CheckBox)standardOfCareList[index]).Checked;
        }

        /// <summary>
        /// Returns the procedure cost (which includes professional fees) for a given visit
        /// </summary>
        /// <param name="index">Visit index</param>
        /// <returns>decimal</returns>
        public decimal GetProcedureCost(int index)
        {
            // The procedure cost is non-zero if the procedure is required and not part of the
            // standard of care for a particular visit.  If overhead is to be applied, we apply it here
            if (GetRequired(index) && !GetStandardOfCare(index))
            {
                decimal procedureCost = decimal.Parse(procedureCharge.Text) + decimal.Parse(profFee.Text);
                if (ApplyOverhead)
                {
                    procedureCost *= 1 + budget.OverheadRate;
                }
                return procedureCost;
            }
            else
                return 0;
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Procedure Charge Code
        /// </summary>
        public string ProcedureChargeCode
        {
            get
            {
                return procedureChargeCode.Text;
            }
        }

        /// <summary>
        /// Procedure Cost
        /// </summary>
        public string ProcedureCost
        {
            get
            {
                return procedureCharge.Text;
            }
        }

        /// <summary>
        /// Procedure name
        /// </summary>
        public string ProcedureName
        {
            get
            {
                return procedureName.Text;
            }
        }

        /// <summary>
        /// Professional fee
        /// </summary>
        public string ProfFee
        {
            get
            {
                return profFee.Text;
            }
        }
        /// <summary>
        /// Procedure Use Hospital Pricing
        /// </summary>
        public string ProcedureUseHospitalPricing
        {
            get
            {
                return procedureUseHospitalPricing.Text;
            }
        }
        /// <summary>
        /// Procedure Facility Pricing
        /// </summary>
        public string ProcedureFacilityPricing
        {
            get
            {
                return procedureFacilityPricing.Text;
            }
        }

        /// <summary>
        /// Apply overhead indicator
        /// </summary>
        public bool ApplyOverhead
        {
            get
            {
                return applyOverhead.Checked;
            }
        }

        /// <summary>
        /// Inpatient indicator
        /// </summary>
        public bool Inpatient
        {
            get
            {
                return inpatient.Checked;
            }
        }

        /// <summary>
        /// Delete indicator
        /// </summary>
        public bool Delete
        {
            get
            {
                return delete.Checked;
            }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// Sets the private Budget Procedure member from the passed in parameter
        /// </summary>
        /// <param name="budgetProcedure"></param>
        /// <param name="Id"></param>
        public BudgetProcedureControl(BudgetProcedure budgetProcedure, string Id)
        {
            this.budgetProcedure = budgetProcedure;
            // Must set the ID here, because we need it in CreateChildControls
            ID = Id;
        }
        #endregion

        #region Overrides
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            EnsureChildControls();
        }

        /// <summary>
        /// Runs upon loading of the control
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            //			EnsureChildControls( );
        }

        /// <summary>
        /// Creates all child controls, applying styles, setting values, and binding validation
        /// </summary>
        protected override void CreateChildControls()
        {
            budget = (Budget)((Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey]).GetCachedObject(Budget.CacheKey);

            //1. apply overhead to procedure
            applyOverhead = new CheckBox();
            applyOverhead.Checked = budgetProcedure.ApplyOverhead;

            //3. inpatient Procedure
            inpatient = new CheckBox();
            inpatient.Checked = budgetProcedure.Inpatient;

            //4. charge
            charge = new Label();
            charge.ID = "charge";
            researchCharge = new Label();

            //5. research Charge
            researchCharge.ID = "researchCharge";
            procedureCharge = new TextBox();

            //6. procedure Charge
            procedureCharge.ID = "procedureCharge";
            procedureCharge.CssClass = "ProcedureControlSmallWidth";
            procedureCharge.Text = budgetProcedure.ProcedureCost;

            //7. prof Fee
            profFee = new TextBox();
            profFee.ID = "profFee";
            profFee.CssClass = "ProcedureControlSmallWidth";
            profFee.Text = budgetProcedure.ProfessionalFee;

            // 2. Setup the Procedure select button
            HtmlInputButton procedurePicker = new HtmlInputButton();
            procedurePicker.Value = "Select Procedure";
            procedurePicker.Attributes["onclick"] = string.Format("window.open('{0}{1}&Institution={2}&Caller={3}', 'Picker', {4});return false;", controlHost, pickerURL, budget.InstitutionCode, ID, features);
            procedurePicker.Attributes["class"] = "Button";
            procedurePicker.Disabled = (budget.StatusCode == ClinicalTrialsConstants.BudgetStatusFinal);
            procedureSpace = new Label();
            procedureSpace.Text = String.Format("&nbsp;&nbsp;");
            procedureName = new Label();
            procedureName.ID = "procedureName";
            procedureName.CssClass = "Label";
            procedureName.Text = budgetProcedure.ProcedureName;
            procedureUseHospitalPricing = new TextBox();
            procedureUseHospitalPricing.ID = "procedureUseHospitalPricing";
            procedureUseHospitalPricing.CssClass = "ControlHidden";
            procedureUseHospitalPricing.Text = (budgetProcedure.UseHospitalPricing==true)?"1" : "0";
            procedureFacilityPricing = new TextBox();
            procedureFacilityPricing.ID = "procedureFacilityPricing";
            procedureFacilityPricing.CssClass = "ControlHidden";
            procedureFacilityPricing.Text = (budgetProcedure.IsFacility == true) ? "1" : "0";
            procedureChargeCode = new TextBox();
            procedureChargeCode.AutoPostBack = true;
            procedureChargeCode.TextChanged += new EventHandler(OnProcedureChanged);
            procedureChargeCode.ID = "procedureChargeCode";
            procedureChargeCode.CssClass = "ControlHidden";
            procedureChargeCode.Text = budgetProcedure.ProcedureChargeCode.ToString();
            OnProcedureChanged(procedureChargeCode, EventArgs.Empty);
            if (budgetProcedure.Id != 0)
            {
                procedureCharge.Text = budgetProcedure.ProcedureCost;
            }

            //8. procedure delete checkbox
            delete = new CheckBox();

            //9. select all Proc and Soc
            selectAllProcReq = new CheckBox();
            selectAllProcReq.AutoPostBack = true;
            selectAllProcReq.CheckedChanged += new EventHandler(OnSelectAllProcChanged);

            selectAllProcSOC = new CheckBox();
            selectAllProcSOC.AutoPostBack = true;
            selectAllProcSOC.CheckedChanged += new EventHandler(OnSelectAllProcChanged);

            // Setup validators

            procedureValidator = new CompareValidator();
            procedureValidator.ErrorMessage = "Procedure is required.";
            procedureValidator.Operator = ValidationCompareOperator.NotEqual;
            procedureValidator.ValueToCompare = "0";
            procedureValidator.Type = ValidationDataType.Integer;
            procedureValidator.Display = ValidatorDisplay.None;
            procedureValidator.ControlToValidate = procedureChargeCode.ID;

            profFeeRequiredValidator = new RequiredFieldValidator();
            profFeeRequiredValidator.ErrorMessage = "Prof Fee is required.  Enter 0 for none.";
            profFeeRequiredValidator.Display = ValidatorDisplay.None;
            profFeeRequiredValidator.ControlToValidate = profFee.ID;

            profFeeFormatValidator = new RegularExpressionValidator();
            profFeeFormatValidator.ErrorMessage = "Prof Fee must be a valid dollar amount.";
            profFeeFormatValidator.Display = ValidatorDisplay.None;
            profFeeFormatValidator.ControlToValidate = profFee.ID;
            profFeeFormatValidator.ValidationExpression = @"^(\+|-)?\d{0,6}(\.\d{1,2})?$";

            procedureChargeRequiredValidator = new RequiredFieldValidator();
            procedureChargeRequiredValidator.ErrorMessage = "Prof Fee is required.  Enter 0 for none.";
            procedureChargeRequiredValidator.Display = ValidatorDisplay.None;
            procedureChargeRequiredValidator.ControlToValidate = procedureCharge.ID;

            procedureChargeFormatValidator = new RegularExpressionValidator();
            procedureChargeFormatValidator.ErrorMessage = "Procedure Charge must be a valid dollar amount.";
            procedureChargeFormatValidator.Display = ValidatorDisplay.None;
            procedureChargeFormatValidator.ControlToValidate = procedureCharge.ID;
            procedureChargeFormatValidator.ValidationExpression = @"\d+\.{0,1}\d{0,2}";

            //tr = new TableRow();
            //cell for description
            TableCell tdDescription = new TableCell();
            tdDescription.Controls.Add(procedureValidator);
            tdDescription.Controls.Add(applyOverhead);
            tdDescription.Controls.Add(procedurePicker);
            tdDescription.Controls.Add(procedureSpace);
            tdDescription.Controls.Add(procedureName);
            tdDescription.Controls.Add(procedureChargeCode);
            tdDescription.Controls.Add(procedureFacilityPricing);
            tdDescription.Controls.Add(procedureUseHospitalPricing);
            Cells.Add(tdDescription);

            //cell for patient
            TableCell tdInpatient = new TableCell();
            tdInpatient.Controls.Add(inpatient);
            Cells.Add(tdInpatient);

            //cell for Charge
            TableCell tdCharge = new TableCell();
            tdCharge.Controls.Add(charge);
            Cells.Add(tdCharge);

            //cell for Research Charge
            TableCell tdResearchCharge = new TableCell();
            tdResearchCharge.Controls.Add(researchCharge);
            Cells.Add(tdResearchCharge);

            //cell for Procedure Charge
            TableCell tdProcedureCharge = new TableCell();
            tdProcedureCharge.Controls.Add(procedureCharge);
            tdProcedureCharge.Controls.Add(procedureChargeRequiredValidator);
            tdProcedureCharge.Controls.Add(procedureChargeFormatValidator);
            Cells.Add(tdProcedureCharge);

            //cell for Prof Fee
            TableCell tdFee = new TableCell();
            tdFee.Controls.Add(profFeeRequiredValidator);
            tdFee.Controls.Add(profFeeFormatValidator);
            tdFee.Controls.Add(profFee);
            Cells.Add(tdFee);

            //cell for delete
            TableCell tdDelete = new TableCell();
            tdDelete.Controls.Add(delete);
            Cells.Add(tdDelete);

            //cell for delete all
            TableCell tdSelectAll = new TableCell();
            tdSelectAll.Controls.Add(selectAllProcReq);
            tdSelectAll.Controls.Add(selectAllProcSOC);
            Cells.Add(tdSelectAll);

            // Setup the controls for each budget milestone visit (checkboxes and cost labels)
            BudgetMilestoneVisits budgetMilestoneVisits = budgetProcedure.BudgetMilestoneVisits;
            for (int i = 0; i < budgetMilestoneVisits.Count; ++i)
            {
                BudgetMilestoneVisit budgetMilestoneVisit = budgetMilestoneVisits[i];
                TableCell BMV = new TableCell();
                CheckBox required = new CheckBox();
                required.ID = string.Format("required{0}", i);
                required.Checked = budgetMilestoneVisit.Required;
                requiredList.Add(required);
                CheckBox standardOfCare = new CheckBox();
                standardOfCare.ID = string.Format("standardOfCare{0}", i);
                standardOfCare.Checked = budgetMilestoneVisit.StandardOfCare;
                standardOfCare.Attributes["onclick"] = "OnCheckedChanged( this );";
                standardOfCareList.Add(standardOfCare);
                HtmlGenericControl span = new HtmlGenericControl();
                span.Attributes["class"] = "Cost";
                Label cost = new Label();
                cost.ID = string.Format("cost{0}", i);
                span.Controls.Add(cost);
                BMV.Controls.Add(required);
                BMV.Controls.Add(standardOfCare);
                BMV.Controls.Add(span);
                Cells.Add(BMV);
            }

            TableCell tdTotal = new TableCell();
            Cells.Add(tdTotal);

        }


        /// <summary>
        /// Used to set the procedure costs just before rendering, because charge codes may have
        /// changed upon postback.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            int visitsCount = budgetProcedure.BudgetMilestoneVisits.Count;
            decimal totalCost = 0;
            for (int i = totalColumnOffset; i < visitsCount + totalColumnOffset; ++i)
            {
                TableCell BMV = Cells[i];
                Label cost = (Label)BMV.Controls[2].Controls[0];
                decimal procCost = GetProcedureCost(i - totalColumnOffset);
                cost.Text = procCost.ToString("c");
                totalCost += procCost;
                if (budget.BudgetProcedures.Count != 0)
                {
                    string tooltip = "header=[Procedure Description] body=[" + procedureName.Text.ToString() + "]";
                    BMV.Attributes.Add("Title", tooltip);
                }
            }
            Cells[visitsCount + totalColumnOffset].Text = totalCost.ToString("c");
            Cells[visitsCount + totalColumnOffset].CssClass = "Label";

            // Format numbers entered by the user
            if (!String.IsNullOrEmpty(procedureCharge.Text))
                procedureCharge.Text = decimal.Parse(procedureCharge.Text).ToString("f");
            // Disable delete checkbox if the task has not been saved yet
            //delete.Enabled = ( budgetProcedure.Id != 0 );
        }
        #endregion

        #region Event Handlers
        /// <summary>
        /// Event handler to process changes to the selected procedure.  Used here to keep
        /// the procedure name on the control since it has no viewstate.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnProcedureChanged(object sender, EventArgs e)
        {
            TextBox chargeCode = (TextBox)sender;
            if (chargeCode.Text.IndexOf(",")>=0)
                chargeCode.Text = chargeCode.Text.Substring(0, chargeCode.Text.IndexOf(","));
            budgetProcedure.UseHospitalPricing = (procedureUseHospitalPricing.Text == "1") ? true : false;
            budgetProcedure.IsFacility = (procedureFacilityPricing.Text == "1") ? true : false;

            SqlDataReader reader = DataAccess.ExecuteReader(DataAccess.GetConnectionString(), "GetClinicalTrialBudgetProcedure",
                DataAccess.BuildSqlParameterArray("@budgetId", SqlDbType.Int, budgetProcedure.BudgetId,
                "@procedureChargeCode", SqlDbType.VarChar, chargeCode.Text,
                "@IsNonFacility", SqlDbType.Bit, (budgetProcedure.IsFacility == true)? 0:1,
                "@UseHospitalPricing", SqlDbType.Bit, (budgetProcedure.UseHospitalPricing == true)? 1:0));
            while (reader.Read())
            {
                procedureName.Text = reader[0].ToString();
                charge.Text = reader.GetDecimal(1).ToString("F");
                researchCharge.Text = reader.GetDecimal(2).ToString("F");
                procedureCharge.Text = charge.Text;
                profFee.Text = reader.GetDecimal(3).ToString("F");
                budgetProcedure.ProcedureChargeCode = Convert.ToInt32(chargeCode.Text);
           }
            reader.Close();
        }
        #endregion

        private void OnSelectAllProcChanged(object sender, EventArgs e)
        {
            if (selectAllProcSOC.Checked)
            {
                for (int i = 0; i < standardOfCareList.Count; ++i)
                {
                    ((CheckBox)standardOfCareList[i]).Checked = true;
                }
            }
            else
            {
                for (int i = 0; i < standardOfCareList.Count; ++i)
                {
                    ((CheckBox)standardOfCareList[i]).Checked = false;
                }

            }
            if (selectAllProcReq.Checked)
            {
                for (int i = 0; i < requiredList.Count; ++i)
                {
                    ((CheckBox)requiredList[i]).Checked = true;
                }
            }
            else
            {
                for (int i = 0; i < requiredList.Count; ++i)
                {
                    ((CheckBox)requiredList[i]).Checked = false;
                }
            }
        }
    }

    #region Class BudgetProcedureControlDesigner
    /// <summary>
    /// Designer associated with the BudgetProcedureControl control.
    /// </summary>
    /// <remarks>
    /// This class cannot be used directly.
    /// </remarks>
    public class BudgetProcedureControlDesigner : ControlDesigner
    {
        #region Overrides
        /// <summary>
        /// Since the BudgetProcedureControl control does not have any design-time visibility, the designer provides
        /// the type name of that control and the name of the instance.
        /// </summary>
        /// <returns>HTML representation of the BudgetProcedureControl control</returns>
        public override string GetDesignTimeHtml()
        {
            return CreatePlaceHolderDesignTimeHtml();
        }
        #endregion
    }
    #endregion
}
